/**
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY), without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.merak.core.text;

import java.io.IOException;

import org.merak.core.model.Identifiable;

/**
 * Copyright © 2010-2012 Merak Computing. All rights reserved.<br><br>
 *
 * The first 256 unicode characters.
 *
 * @author fmarinho.
 * @version 1.00.00 - Jul 22, 2012 - fmarinho - initial version.
 *
 * @since MerakCore 1.00.00
 */
public enum UNICODE256 implements Identifiable<Character> {

	// ~ CONTROL ///////////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
    NUL( 0), // u0000  null
    SOH( 1), // u0001  start of heading
    STX( 2), // u0002  start of text
    ETX( 3), // u0003  end of text
    EOT( 4), // u0004  end of transmission
    ENQ( 5), // u0005  enquiry
    ACK( 6), // u0006  acknowledge
    BEL( 7), // u0007  bell
    BS ( 8), // \b     backspace
    TAB( 9), // \t     horizontal tab
    LF (10), // \n     NL line feed, new line
    VT (11), // u000B  vertical tab
    FF (12), // \f     NP form feed, new page
    CR (13), // \r     carriage return
    SO (14), // u000E  shift out
    SI (15), // u000F  shift in
    DLE(16), // u0010  data link escape
    DC1(17), // u0011  device control 1
    DC2(18), // u0012  device control 2
    DC3(19), // u0013  device control 3
    DC4(20), // u0014  device control 4
    NAK(21), // u0015  negative acknowledge
    SYN(22), // u0016  synchronous idle
    ETB(23), // u0017  end of transmission block
    CAN(24), // u0018  cancel
    EM (25), // u0019  end of medium
    SUB(26), // u001A  substitute
    ESC(27), // u001B  escape
    FS (28), // u001C  file separator
    GS (29), // u001D  group separator
    RS (30), // u001E  record separator
    US (31), // u001F  unit separator

	// ~ PUNCTUATION ///////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
    SPACE            (32 ),   // blank space
    EXCLAMATION      ('!'),
    QUOTATION        ('"'),
    NUMBER           ('#'),
    DOLLAR           ('$'),
    PERCENT          ('%'),
    AMPERSAND        ('&'),
    APOSTROPHE       ('\''),
    LEFT_PARENTHESIS ('('),
    RIGHT_PARENTHESIS(')'),
    ASTERISK         ('*'),
    PLUS             ('+'),
    COMMA            (','),
    HYPHEN_MINUS     ('-'),
    PERIOD           ('.'),
    SLASH            ('/'),

	// ~ DIGIT /////////////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
    ZERO('0'),  ONE('1'),  TWO  ('2'),  THREE('3'),  FOUR('4'),
    FIVE('5'),  SIX('6'),  SEVEN('7'),  EIGHT('8'),  NINE('9'),

	// ~ PUNCTUATION ///////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
    COLON        (':'),
    SEMICOLON    (';'),
    LESS_THAN    ('<'),
    EQUAL        ('='),
    GREATER_THAN ('>'),
    QUESTION     ('?'),
    AT           ('@'),

	// ~ UPPERCASE /////////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
    A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,

	// ~ PUNCTUATION ///////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
    LEFT_BRACKET ('['),
    BACKSLASH    ('\\'),
    RIGHT_BRACKET(']'),
    CIRCUMFLEX   ('^'),
    UNDERSCORE   ('_'),
    GRAVE        ('`'),

	// ~ LOWERCASE /////////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
    a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,

	// ~ PUNCTUATION ///////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
    LEFT_BRACE  ('{'),
    VERTICAL_BAR('|'),
    RIGHT_BRACE ('}'),
    TILDE       ('~'),

	// ~ CONTROL ///////////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
    DEL                                    (127),  // u007F  delete
    PADDING                                (128),  // u0080
    HIGH_OCTET_PRESET                      (129),  // u0081
    BREAK_PERMITTED_HERE                   (130),  // u0082
    NO_BREAK_HERE                          (131),  // u0083
    INDEX                                  (132),  // u0084
    NEXT_LINE                              (133),  // u0085
    START_OF_SELECTED_AREA                 (134),  // u0086
    END_OF_SELECTED_AREA                   (135),  // u0087
    CHARACTER_TABULATION_SET               (136),  // u0088
    CHARACTER_TABULATION_WITH_JUSTIFICATION(137),  // u0089
    LINE_TABULATION_SET                    (138),  // u008A
    PARTIAL_LINE_FORWARD                   (139),  // u008B
    PARTIAL_LINE_BACKWARD                  (140),  // u008C
    REVERSE_LINE_FEED                      (141),  // u008D
    SINGLE_SHIFT_TWO                       (142),  // u008E
    SINGLE_SHIFT_THREE                     (143),  // u008F
    DEVICE_CONTROL_STRING                  (144),  // u0090
    PRIVATE_USE_1                          (145),  // u0091
    PRIVATE_USE_2                          (146),  // u0092
    SET_TRANSMIT_STATE                     (147),  // u0093
    CANCEL_CHARACTER                       (148),  // u0094
    MESSAGE_WAITING                        (149),  // u0095
    START_OF_PROTECTED_AREA                (150),  // u0096
    END_OF_PROTECTED_AREA                  (151),  // u0097
    START_OF_STRING                        (152),  // u0098
    SINGLE_GRAPHIC_CHARACTER_INTRODUCER    (153),  // u0099
    SINGLE_CHARACTER_INTRO_INTRODUCER      (154),  // u009A
    CONTROL_SEQUENCE_INTRODUCER            (155),  // u009B
    STRING_TERMINATOR                      (156),  // u009C
    OPERATING_SYSTEM_COMMAND               (157),  // u009D
    PRIVATE_MESSAGE                        (158),  // u009E
    APPLICATION_PROGRAM_COMMAND            (159),  // u009F

	// ~ PUNCTUATION ///////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
    NBSP(160),                       // Non-breaking space
    INVERTED_EXCLAMATION('¡'),       // Inverted Exclamation Mark
    CENT('¢'),                       // Cent sign
    POUND('£'),                      // Pound sign
    CURRENCY('¤'),                   // Currency sign
    YEN('¥'),                        // Yen sign
    BROKEN_BAR('¦'),                 // Broken bar
    SECTION('§'),                    // Section sign
    DIARESIS('¨'),                   // Diaeresis
    COPYRIGHT('©'),                  // Copyright sign
    FEMININE_ORDINAL('ª'),           // Feminine Ordinal Indicator
    DOUBLE_ANGLE_QUOTATION('«'),     // Left-pointing double angle quotation mark
    NOT('¬'),                        // Not sign
    SOFT_HYPHEN(173),                // u00AD Soft hyphen
    REGISTERED('®'),                 // Registered sign
    MACRON('¯'),                     // Macron
    DEGREE('°'),                     // Degree symbol
    PLUS_MINUS('±'),                 // Plus-minus sign
    SUPERSCRIPT2('²'),               // Superscript two
    SUPERSCRIPT3('³'),               // Superscript three
    ACUTE('´'),                      // Acute accent
    MICRO('µ'),                      // Micro sign
    PILCROW('¶'),                    // Pilcrow sign
    MIDDLE_DOT('·'),                 // Middle dot
    CEDILLA('¸'),                    // Cedilla
    SUPERSCRIPT1('¹'),               // superscript one
    MASCULINE_ORDINAL('º'),          // Masculine ordinal indicator
    RIGHT_DOUBLE_ANGLE_QUOTE('»'),   // Right-pointing double angle quotation mark
    ONE_QUARTER('¼'),                // Vulgar fraction one quarter
    ONE_HALF('½'),                   // Vulgar fraction one half
    THREE_QUARTERS('¾'),             // Vulgar fraction three quarters
    INVERTED_QUESTION('¿'),          // Inverted Question Mark

	// ~ UPPERCASE WITH ACCENT /////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
    À,Á,Â,Ã,Ä,Å,Æ,Ç,È,É,Ê,Ë,Ì,Í,Î,Ï,Ð,Ñ,Ò,Ó,Ô,Õ,Ö,MULTIPLICATION('×'),Ø,Ù,Ú,Û,Ü,Ý,
    CAPITAL_LETTER_THORN('Þ'),  // Latin Capital Letter Thorn
    SMALL_LETTER_SHARP('ß'),    // Latin Small Letter sharp S

	// ~ LOWERCASE WITH ACCENT /////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
    à,á,â,ã,ä,å,æ,ç,è,é,ê,ë,ì,í,î,ï,ð,ñ,ò,ó,ô,õ,ö,DIVISION('÷'),ø,ù,ú,û,ü,ý,
    SMALL_LETTER_THORN('þ'),    // Latin Small Letter Thorn
    ÿ;                          // Latin Small Letter Y with diaeresis

	// ~ Attributes ////////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
    private static final UNICODE256[] index = UNICODE256.values();

    private final Character id;
    private final String    escape;
    private final boolean   isControl;

	// ~ Constructors //////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
	private UNICODE256() {

		// Both id and escape are the character itself
		this.id        = super.toString().charAt(0);
		this.escape    = String.valueOf(this.id);
		this.isControl = Character.isISOControl(this.id);

	}
	//**********************************************************************************************
	private UNICODE256(int id) {

		// The id is the character itself
		this.id        = (char) id;
		this.isControl = Character.isISOControl(this.id);

		// Escape characters, worrying about control characters
		if ( ! Character.isISOControl(this.id) ) {
			switch(this.id) {
				case '\\': this.escape = "\\\\"; break;
				default  : this.escape = String.valueOf(this.id);
			}
		}
		else {
			switch(this.id) {
				case '\b': this.escape = "\\b"; break;
				case '\t': this.escape = "\\t"; break;
				case '\n': this.escape = "\\n"; break;
				case '\f': this.escape = "\\f"; break;
				case '\r': this.escape = "\\r"; break;
				default  : this.escape = String.format("\\u%04X",(int)this.id);
			}
		}

	}

	// ~ Methods ///////////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
	/**
	 * Returns the unicode character's numerical representation as identifier
	 * @since v 1.00.00
	 */
	@Override
	public Character getId() {
		return this.id;
	}
	//**********************************************************************************************
	/**
	 * Returns the character named name in the Unicode database (Unicode only)
	 * @since v 1.00.00
	 */
	public String getName() {
		return super.toString();
	}
	//**********************************************************************************************
	/**
	 * Returns the escaped character or the character itself if no escape is necessary.
	 * @since v 1.00.00
	 */
	public String getEscape() {
		return this.escape;
	}
	//**********************************************************************************************
	/**
	 * Returns if the character is ISO control character.
	 * @since v 1.00.00
	 */
	public boolean isControl() {
		return this.isControl;
	}
	//**********************************************************************************************
	/* (non-Javadoc)
	 * @see org.merak.core.model.Identifiable#hasId(java.io.Serializable)
	 */
	@Override
	public boolean hasId(Character id) {
		return this.id.equals(id);
	}
	//**********************************************************************************************
	/* (non-Javadoc)
	 * @see org.merak.core.model.Identifiable#anonymous()
	 */
	@Override
	public boolean anonymous() {
		return false;
	}
	//**********************************************************************************************
	/* (non-Javadoc)
	 * @see org.merak.core.model.Identifiable#selfsame(org.merak.core.model.Identifiable)
	 */
	@Override
	public boolean selfsame(Identifiable<Character> obj) {
		return obj == this;
	}
	//**********************************************************************************************
	@Override
	public String toString() {
		return this.escape;
	}
	//**********************************************************************************************
	public static final UNICODE256 getValue(int ch) {

		return (ch<index.length) ? index[ch] : null;

	}
	//**********************************************************************************************
	public static final int length() {

		return index.length;

	}
	//**********************************************************************************************
	public static final String escape(char ch) {

		return (ch<index.length) ? index[ch].getEscape() : String.valueOf(ch);

	}
	//**********************************************************************************************
	public static final Appendable escape(char ch,Appendable buffer) throws IOException {

		if (ch == BACKSLASH.id) {
			return buffer.append(BACKSLASH.escape);
		}

		if (ch<index.length && index[ch].isControl) {
			return buffer.append(index[ch].escape);
		}
		else {
			return buffer.append(ch);
		}

	}
	//**********************************************************************************************
	public static final Appendable escape(CharSequence str,Appendable buffer) throws IOException {

		int len = str.length();
		for (int i=0; i<len; i++) escape(str.charAt(i),buffer);
		return buffer;

	}
	//**********************************************************************************************
	public static final Appendable escapeQuoted(char ch,Appendable buffer) throws IOException {

		return (ch == QUOTATION.id) ? buffer.append("\\\"") : escape(ch,buffer);

	}
	//**********************************************************************************************
	public static final Appendable escapeQuoted(CharSequence str,Appendable buffer)
			throws IOException
	{

		int len = str.length();
		for (int i=0; i<len; i++) escapeQuoted(str.charAt(i),buffer);
		return buffer;

	}
	//**********************************************************************************************
	public static final Appendable escapeSingleQuoted(char ch,Appendable buffer)
			throws IOException
	{

		return (ch == APOSTROPHE.id) ? buffer.append("\\'") : escape(ch,buffer);

	}
	//**********************************************************************************************
	public static final Appendable escapeSingleQuoted(CharSequence str,Appendable buffer)
			throws IOException
	{

		int len = str.length();
		for (int i=0; i<len; i++) escapeSingleQuoted(str.charAt(i),buffer);
		return buffer;

	}
	//**********************************************************************************************
}
